// Enesea Linux Window
// (c) jimon game studio

#include "CWindow_Linux.h"
#include "ILogManager.h"
#include "CMouseDriver.h"
#include "CKeyDriver.h"
#include "IVariables.h"

#ifdef JE_DEVICE_LINUX

namespace je
{
	namespace device
	{
		//! Constructor
		CWindow_Linux::CWindow_Linux(Display * XDisplay,const jeVector2di & size,const jeStringd & Title,u1 fullscreen,s32 depth,s32 hertz,s32 msaa)
			:CurrentDisplay(XDisplay),FullScreenMode(fullscreen),WindowActived(false),MainWindow(false),NeedClose(false),Size(size),CurrentDepth(depth),CurrentHertz(hertz),CurrentMSAA(msaa)
		{
			CurrentScreen = DefaultScreen(CurrentDisplay);

			s32 GLXAttributes[] = {	GLX_RENDER_TYPE,GLX_RGBA_BIT,
									GLX_DRAWABLE_TYPE,GLX_WINDOW_BIT,
									GLX_DOUBLEBUFFER,true,
									GLX_X_RENDERABLE,true,
									GLX_X_VISUAL_TYPE,GLX_TRUE_COLOR,
									GLX_SAMPLE_BUFFERS,true,
									GLX_SAMPLES,CurrentMSAA,
									GLX_RED_SIZE,8,
									GLX_GREEN_SIZE,8,
									GLX_BLUE_SIZE,8,
									GLX_ALPHA_SIZE,8,
									GLX_DEPTH_SIZE,24,
									GLX_STENCIL_SIZE,8,
									NULL
									};

			s32 FrameBuffersCount;
			FrameBufferConfig = glXChooseFBConfig(CurrentDisplay,CurrentScreen,GLXAttributes,&FrameBuffersCount);

			if(FrameBuffersCount == 0)
			{
				JELOG_E("Cant retrive glx frame buffer config !")
				return;
			}

			CurrentVisualInfo = glXGetVisualFromFBConfig(CurrentDisplay,FrameBufferConfig[0]);

			XSetWindowAttributes CurrentWindowAttributes;
			CurrentWindowAttributes.colormap = XCreateColormap(CurrentDisplay,RootWindow(CurrentDisplay,CurrentVisualInfo->screen),CurrentVisualInfo->visual,AllocNone);
			CurrentWindowAttributes.border_pixel = 0;
			CurrentWindowAttributes.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask;

			if(FullScreenMode)
			{
				XF86VidModeModeInfo ** AdapterModes;
				s32 AdapterModesCount,UseMode;

				XF86VidModeGetAllModeLines(CurrentDisplay,CurrentScreen,&AdapterModesCount,&AdapterModes);

				LastDesktopMode = *AdapterModes[0];
				for(s32 i = 0;i<AdapterModesCount;i++)
					if((AdapterModes[i]->hdisplay == Size.X) && (AdapterModes[i]->vdisplay == Size.Y))
					{
						UseMode = i;
						break;
					}

				XF86VidModeSwitchToMode(CurrentDisplay,CurrentScreen,AdapterModes[UseMode]);
				XF86VidModeSetViewPort(CurrentDisplay,CurrentScreen,0,0);
				XFree(AdapterModes);

				CurrentWindowAttributes.override_redirect = true;

				CurrentWindow = XCreateWindow(CurrentDisplay,RootWindow(CurrentDisplay,CurrentVisualInfo->screen),0,0,Size.X,Size.Y,0,CurrentVisualInfo->depth,InputOutput,CurrentVisualInfo->visual,CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,&CurrentWindowAttributes);
				XWarpPointer(CurrentDisplay,None,CurrentWindow,0,0,0,0,0,0);
				XMapRaised(CurrentDisplay,CurrentWindow);
				XGrabKeyboard(CurrentDisplay,CurrentWindow,true,GrabModeAsync,GrabModeAsync,CurrentTime);
				XGrabPointer(CurrentDisplay,CurrentWindow,true,ButtonPressMask,GrabModeAsync,GrabModeAsync,CurrentWindow,None,CurrentTime);
			}
			else
			{
				CurrentWindow = XCreateWindow(CurrentDisplay,RootWindow(CurrentDisplay,CurrentVisualInfo->screen),0,0,Size.X,Size.Y,0,CurrentVisualInfo->depth,InputOutput,CurrentVisualInfo->visual,CWBorderPixel | CWColormap | CWEventMask,&CurrentWindowAttributes);
				Atom WindowModemDelete = XInternAtom(CurrentDisplay,"WM_DELETE_WINDOW",True);
        		XSetWMProtocols(CurrentDisplay,CurrentWindow,&WindowModemDelete, 1);
        		jeStringc Title_C = Title.c_str();
				XSetStandardProperties(CurrentDisplay,CurrentWindow,Title_C.c_str(),Title_C.c_str(),None,NULL,0,NULL);
				XMapRaised(CurrentDisplay,CurrentWindow);
			}

			Window TempRootWindow;
			u32 TempSizeX,TempSizeY,TempBorder,TempDepth;
			XGetGeometry(CurrentDisplay,CurrentWindow,&TempRootWindow,&Position.X,&Position.Y,&TempSizeX,&TempSizeY,&TempBorder,&TempDepth);
			Size.SetXY(TempSizeX,TempSizeY);
			CurrentDepth = TempDepth;

			JENEW(MouseDriver,input::CMouseDriver(this))
			JENEW(KeyDriver,input::CKeyDriver(this))
		}

		//! Destructor
		CWindow_Linux::~CWindow_Linux()
		{
			if(FullScreenMode)
			{
				XF86VidModeSwitchToMode(CurrentDisplay,CurrentScreen,&LastDesktopMode);
				XF86VidModeSetViewPort(CurrentDisplay,CurrentScreen,0,0);
			}
			XDestroyWindow(CurrentDisplay,CurrentWindow);

			KeyDriver->Drop();
			MouseDriver->Drop();
		}

		//! Set Window Active
		void CWindow_Linux::SetActive(u1 Active)
		{
			WindowActived = Active;
		}

		//! Set Close Flag
		void CWindow_Linux::SetCloseFlag(u1 Close)
		{
			NeedClose = Close;
		}

		//! Resize Window
		void CWindow_Linux::Resize(const jeVector2di & NewSize)
		{
			Size = NewSize;
		}

		//! Set Size
		void CWindow_Linux::SetSize(const jeVector2di & NewSize)
		{
			if(FullScreenMode)
				SetFullScreen(true,NewSize);
			else
				XResizeWindow(CurrentDisplay,CurrentWindow,NewSize.X,NewSize.Y);
			Size = NewSize;
		}

		//! Get Size
		const jeVector2di & CWindow_Linux::GetSize()
		{
			return Size;
		}

		//! Set Window Position
		void CWindow_Linux::SetPosition(const jeVector2di & NewPosition)
		{
			Position = NewPosition;
			XMoveWindow(CurrentDisplay,CurrentWindow,Position.X,Position.Y);
		}

		//! Get Window Position
		const jeVector2di & CWindow_Linux::GetPosition()
		{
			return Position;
		}

		//! Set Fullscreen Mode
		void CWindow_Linux::SetFullScreen(u1 FullScreen,const jeVector2di & NewSize,s32 Depth,s32 Hertz)
		{
//			if(FullScreen)
//			{
//				DEVMODE mode;
//				ZeroMemory(&mode, sizeof(DEVMODE));
//				mode.dmSize = sizeof(DEVMODE);
//				mode.dmPelsWidth = NewSize.X;
//				mode.dmPelsHeight = NewSize.Y;
//				mode.dmBitsPerPel = Depth;
//				CurrentDepth = Depth;
//				mode.dmDisplayFrequency = Hertz;
//				CurrentHertz = Hertz;
//				mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
//				SetWindowLong(WindowHandle,GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_TOPMOST);
//				SetWindowLong(WindowHandle,GWL_STYLE, WS_POPUP);
//				SetWindowPos(WindowHandle,HWND_TOPMOST, 0, 0,NewSize.X,NewSize.Y,SWP_SHOWWINDOW | SWP_FRAMECHANGED);
//				if(ChangeDisplaySettings(&mode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
//				{
//					SetFullScreen(false,NewSize);
//					return;
//				}
//			}
//			else
//			{
//				SetWindowLong(WindowHandle,GWL_EXSTYLE,WS_EX_APPWINDOW);
//				SetWindowLong(WindowHandle,GWL_STYLE,WS_OVERLAPPEDWINDOW);
//				SetWindowPos(WindowHandle,HWND_TOP,0,0,NewSize.X,NewSize.Y, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
//				if(ChangeDisplaySettings(&DefaultMode, 0) != DISP_CHANGE_SUCCESSFUL)
//				{
//					JELOG_E("Cant change window settings to default")
//					return;
//				}
//			}

			Size = NewSize;
			FullScreenMode = FullScreen;
		}

		//! Return true if fullscreen
		u1 CWindow_Linux::IsFullScreen()
		{
			return FullScreenMode;
		}

		//! Get Depth
		s32 CWindow_Linux::GetDepth()
		{
			return CurrentDepth;
		}

		//! Get Hertz
		s32 CWindow_Linux::GetHertz()
		{
			return CurrentHertz;
		}

		//! Get MSAA
		s32 CWindow_Linux::GetMSAA()
		{
			return CurrentMSAA;
		}

		//! Set Window Title
		void CWindow_Linux::SetTitle(const jeStringd & Title)
		{
			wchar_t * TitleTemp = NULL;
			JENEW_A(TitleTemp,wchar_t,Title.size())
			jeschar * TitleSysTemp = const_cast<jeschar*>(Title.c_str());
			for(u32 i=0;i<Title.size();i++)
				TitleTemp[i] =  TitleSysTemp[i];
			XTextProperty txt;
			XwcTextListToTextProperty(CurrentDisplay,&TitleTemp,1,XStdICCTextStyle,&txt);
			XSetWMName(CurrentDisplay,CurrentWindow,&txt);
			XSetWMIconName(CurrentDisplay,CurrentWindow,&txt);
			XFree(txt.value);
			JEDELETE_A(TitleTemp)
		}

		//! Get Window Title
		jeStringd CWindow_Linux::GetTitle()
		{
			XTextProperty txt;
			XGetWMName(CurrentDisplay,CurrentWindow,&txt);
			jeStringd Title = txt.value;
			XFree(txt.value);
			return Title;
		}

		//! Set Main Window flag
		void CWindow_Linux::SetMainWindow(u1 Main)
		{
			MainWindow = Main;
		}

		//! Return Main Window flag
		u1 CWindow_Linux::IsMainWindow()
		{
			return MainWindow;
		}

		//! Return true if someone try to close window
		u1 CWindow_Linux::IsNeedToClose()
		{
			return NeedClose;
		}

		//! Return true if window active
		u1 CWindow_Linux::IsActive()
		{
			return WindowActived;
		}

		//! Set Focus on window
		void CWindow_Linux::SetWindowFocus()
		{
			//SetFocus(WindowHandle);
		}

		//! Get Mouse Driver
		input::IMouseDriver * CWindow_Linux::GetMouseDriver()
		{
			return MouseDriver;
		}

		//! Get Key Driver
		input::IKeyDriver * CWindow_Linux::GetKeyDriver()
		{
			return KeyDriver;
		}

		//! Get Window Api Pointer
		void * CWindow_Linux::GetWindowApiPointer(WindowApiPointerType Type)
		{
			switch(Type)
			{
			case WAPT_X_DEVICE:
				return CurrentDisplay;
			case WAPT_X_WINDOW:
				return &CurrentWindow;
			case WAPT_X_VISUAL_INFO:
				return CurrentVisualInfo;
			case WAPT_X_FRAMEBUFFER_CONFIG:
				return FrameBufferConfig;
			default:
				return NULL;
			}
		}

	}
}

#endif
